﻿using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Configuration;
using System.Collections.Generic;
using System.Threading;
using log4net;

namespace NVRCsharpDemo
{
    public partial class MainWindow : Form
    {
        private bool m_bInitSDK = false;
        private uint iLastErr = 0;
        private Int32 i = 0;
        private string str;
        private Device enterDevice;
        private Device exitDevice;
        private MessageHandler messageHandler;
        private DbWorker worker = new DbWorker();
        private ILog logger = LogManager.GetLogger("MainWindow");

        public MainWindow()
        {
            InitializeComponent();
            foreach (ColumnHeader item in carInfoListView.Columns)
            {
                switch (item.Name)
                {
                    case "plateNumber":
                        item.Width = (carInfoListView.Width / 100) * 40;
                        break;
                    case "enterTime":
                        item.Width = (carInfoListView.Width / 100) * 40;
                        break;
                    case "exitTime":
                        item.Width = (carInfoListView.Width / 100) * 10;
                        break;
                    default:
                        item.Width = -2;
                        break;
                }
            }
            carInfoListView.Invalidate();
            refreshCarInfoList();
            m_bInitSDK = CHCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                logger.Info("NET_DVR_Init error!");
                MessageBox.Show("NET_DVR_Init error!");
            }
            else
            {
                CHCNetSDK.NET_DVR_SetConnectTime(2000, 2);
                CHCNetSDK.NET_DVR_SetReconnect(10000, 1);
                //保存SDK日志 To save the SDK log
                CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
                messageHandler = new MessageHandler();
                messageHandler.NotifyUpdateCarInfo = refreshCarInfoList;
                CHCNetSDK.NET_DVR_SetDVRMessageCallBack_V30(new CHCNetSDK.MSGCallBack(messageHandler.MessageCallBack), IntPtr.Zero);
            }
            loadCarPort();
        }

        public void DebugInfo(string str)
        {
            if (str.Length > 0)
            {
                str += "\n";
            }
            logger.Info(str);
        }

        private void StartPreview(Device device, PictureBox realPlayWnd)
        {
            if (device.uid < 0)
            {
                logger.Info("Please login the device firstly!");
                MessageBox.Show("Please login the device firstly!");
                return;
            }

            if (device.realHandle > 0)
            {
                logger.Info("The device is previewed");
                return;
            }
            CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
            lpPreviewInfo.hPlayWnd = realPlayWnd.Handle;//预览窗口 live view window
            if (device.channels.Length > 0)
            {
                lpPreviewInfo.lChannel = device.channels[0];//预览的设备通道 the device channel number
            }
            else
            {
                logger.Info("Error!!, No preview channel. Stop preview");
                MessageBox.Show("Error!!, No preview channel. Stop preview");
                return;
            }
            lpPreviewInfo.dwStreamType = 0;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
            lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
            lpPreviewInfo.bBlocked = true; //0- 非阻塞取流，1- 阻塞取流
            lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数

            IntPtr pUser = IntPtr.Zero;//用户数据 user data 
            device.realHandle = CHCNetSDK.NET_DVR_RealPlay_V40(device.uid, ref lpPreviewInfo, null/*RealData*/, pUser);
            if (device.realHandle < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_RealPlay_V40 failed, error code= " + iLastErr; //预览失败，输出错误号 failed to start live view, and output the error code.
                DebugInfo(str);
                return;
            }
            else
            {
                //预览成功
                DebugInfo("NET_DVR_RealPlay_V40 succ! " + device.realHandle);
            }

        }

        private void StopPreview(Device device, PictureBox realPlayWnd)
        {
            logger.Info("Stop preview");
            if (device.realHandle < 0)
            {
                return;
            }
            //停止预览 Stop live view 
            if (!CHCNetSDK.NET_DVR_StopRealPlay(device.realHandle))
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_StopRealPlay failed, error code= " + iLastErr;
                DebugInfo(str);
            }
            else
            {
                DebugInfo("NET_DVR_StopRealPlay succ!");
                device.realHandle = -1;
                realPlayWnd.Invalidate();//刷新窗口 refresh the window
            }
        }

        private void RefreshPreview(Device device, PictureBox realPlayWnd)
        {
            StopPreview(device, realPlayWnd);
            if (device.realHandle == -1)
            {
                StartPreview(device, realPlayWnd);
            }
        }

        private void enter_config_btn_Click(object sender, EventArgs e)
        {
            if (this.enterDevice != null)
            {
                return;
            }
            Device device = Device.GetEnterDevice();
            this.enterDevice = Login(device.ipAddress, 8000, device.username, device.password);
            if (enterDevice != null)
            {
                enter_device_name_label.Text = this.enterDevice.serial;
                this.ConfigChannel(enterDevice);
                this.StartPreview(enterDevice, EnterRealPlayWnd);
                messageHandler.EnterDevice = enterDevice;
                this.EnableCarAlarm(enterDevice);
            }

        }

        private void exit_config_btn_Click(object sender, EventArgs e)
        {
            if (this.exitDevice != null)
            {
                return;
            }
            Device device = Device.GetExitDevice();
            this.exitDevice = Login(device.ipAddress, 8000, device.username, device.password);
            if (this.exitDevice != null)
            {
                exit_device_name_label.Text = this.exitDevice.serial;
                this.ConfigChannel(exitDevice);
                this.StartPreview(exitDevice, ExitRealPlayWnd);
                messageHandler.ExitDevice = exitDevice;
                this.EnableCarAlarm(exitDevice);
            }
        }

        private Device Login(String ipAddress, Int32 port, String username, String password)
        {
            logger.InfoFormat(String.Format("Login device with {0}, {1}, {2}", ipAddress, port, username));
            CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();

            //登录设备 Login the device
            int uid = CHCNetSDK.NET_DVR_Login_V30(ipAddress, port, username, password, ref DeviceInfo);
            if (uid < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Login_V30 failed, error code= " + iLastErr; //登录失败，输出错误号
                logger.Info(str);
                MessageBox.Show(str);
                return null;
            }
            else
            {
                //登录成功
                logger.InfoFormat(String.Format("Login succuss with {0}, {1}, {2}", ipAddress, port, username));
                Device device = new Device
                {
                    uid = uid,
                    deviceInfo = DeviceInfo,
                    serial = Encoding.UTF8.GetString(DeviceInfo.sSerialNumber),
                    ipAddress = ipAddress
                };
                return device;
            }
        }

        private void Logout(Device device)
        {
            if (!CHCNetSDK.NET_DVR_Logout(device.uid))
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Logout failed, error code= " + iLastErr;
                DebugInfo(str);
            }
            else
            {
                DebugInfo("NET_DVR_Logout succ!");
            }
        }

        private void ConfigChannel(Device device)
        {
            CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = device.deviceInfo;
            device.channelNum = (uint)DeviceInfo.byChanNum;
            if (device.channelNum > 0)
            {
                device.channels = new int[device.channelNum];
                for (i = 0; i < device.channelNum; i++)
                {
                    device.channels[i] = i + (int)DeviceInfo.byStartChan;
                }
            }
            else
            {
                logger.Info("设备异常，无法查看。");
                MessageBox.Show("设备异常，无法查看。");
            }
        }

        private void MainWindow_Closing(object sender, FormClosingEventArgs e)
        {
            Console.WriteLine("close " + enterDevice);
            if (enterDevice != null)
            {
                messageHandler.EnterDevice = null;
                CloseDevice(enterDevice, EnterRealPlayWnd);
            }
            if (exitDevice != null)
            {
                messageHandler.ExitDevice = null;
                CloseDevice(exitDevice, ExitRealPlayWnd);
            }
        }

        private void CloseDevice(Device device, PictureBox realPlayWnd)
        {
            logger.Info("close device: " + device.realHandle);
            if (device.realHandle >= 0)
            {
                StopPreview(device, realPlayWnd);
            }
            if (device.alarmHandle >= 0)
            {
                DisableCarAlarm(device);
            }
            if (device.uid >= 0)
            {
                Logout(device);
            }
        }

        private void EnableCarAlarm(Device device)
        {
            CHCNetSDK.NET_DVR_SETUPALARM_PARAM struAlarmParam = new CHCNetSDK.NET_DVR_SETUPALARM_PARAM();
            struAlarmParam.dwSize = (uint)Marshal.SizeOf(struAlarmParam);
            struAlarmParam.byLevel = 1; //0- 一级布防,1- 二级布防
            struAlarmParam.byAlarmInfoType = 1;//智能交通设备有效，新报警信息类型
            struAlarmParam.byFaceAlarmDetection = 0;//1-人脸侦测

            device.alarmHandle = CHCNetSDK.NET_DVR_SetupAlarmChan_V41(device.uid, ref struAlarmParam);
            if (device.alarmHandle < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                str = "布防失败，错误号：" + iLastErr; //布防失败，输出错误号
                logger.Info(str);
                MessageBox.Show(str);
            }
            else
            {
                logger.Info("布防成功");
            }
        }

        private void DisableCarAlarm(Device device)
        {
            if (device.alarmHandle >= 0)
            {
                if (!CHCNetSDK.NET_DVR_CloseAlarmChan_V30(device.alarmHandle))
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    str = "撤防失败，错误号：" + iLastErr; //撤防失败，输出错误号
                    logger.Info(str);
                    MessageBox.Show(str);
                }
                else
                {
                    logger.Info("撤防成功");
                }
            }
            else
            {
                MessageBox.Show("未布防");
            }
        }
        private void enter_refresh_btn_Click(object sender, EventArgs e)
        {
            if (enterDevice != null)
            {
                RefreshPreview(enterDevice, EnterRealPlayWnd);
            }
        }

        private void exit_refresh_btn_Click(object sender, EventArgs e)
        {
            if (exitDevice != null)
            {
                RefreshPreview(exitDevice, ExitRealPlayWnd);
            }
        }

        private void RefreshData_Click(object sender, EventArgs e)
        {
            loadCarPort();
            new Thread(messageHandler.run).Start();
        }

        private void addCar()
        {
            String[] types = { "小型车", "大型车" };
            Random random = new Random();
            for (int i = 0; i < 3; i++)
            {
                int id = worker.Insert("川A" + RandomString(5), types[random.Next(2)], DateTime.Now.ToString("s"));
                refreshCarInfoList();
            }
        }

        private string RandomString(int size)
        {
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            char ch;
            for (int i = 0; i < size; i++)
            {
                ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
                builder.Append(ch);
            }

            return builder.ToString();
        }

        private void loadCarPort()
        {
            int totalCarport = Int32.Parse(ConfigurationManager.AppSettings["totalCarport"]);
            int bigCarport = Int32.Parse(ConfigurationManager.AppSettings["bigCarport"]);
            int smallCarport = Int32.Parse(ConfigurationManager.AppSettings["smallCarport"]);
            int bigCarNum = worker.QueryBigCarCount();
            int smallCarNum = worker.QuerySmallCarCount();

            totalCarportLabel.Text = totalCarport.ToString();
            remainCarPortLabel.Text = (totalCarport - bigCarNum - smallCarNum).ToString();
            bigCarportLabel.Text = (bigCarport - bigCarNum).ToString();
            smallCarportLabel.Text = (smallCarport - smallCarNum).ToString();
        }

        public void refreshCarInfoList()
        {
            if (carInfoListView.InvokeRequired)
            {
                this.Invoke(new Action(refreshCarInfoList));
                return;
            }
            this.carInfoListView.BeginUpdate();   //数据更新，UI暂时挂起，直到EndUpdate绘制控件，可以有效避免闪烁并大大提高加载速度
            
                this.carInfoListView.Items.Clear();
            List<CarInfo> carInfos = worker.QueryExistedCar(0, 50);
            foreach (CarInfo carInfo in carInfos)
            {
                ListViewItem lvi = new ListViewItem();
                lvi.ImageIndex = i;     //通过与imageList绑定，显示imageList中第i项图标
                lvi.Text = carInfo.plateNumber;
                lvi.SubItems.Add(carInfo.enterTime);
                if (carInfo.exitTime == null)
                {
                    lvi.SubItems.Add("");
                }
                else
                {
                    lvi.SubItems.Add(carInfo.exitTime);
                }
                this.carInfoListView.Items.Add(lvi);
            }
            this.carInfoListView.EndUpdate();
            loadCarPort();
        }

        private void resetBtn_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("请再次确定要重置数据么？重置数据后所有停车信息将消失。",
                "重置数据",
                MessageBoxButtons.OKCancel,
                MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button2) == DialogResult.OK)

            {
                new Thread(messageHandler.Reset).Start();
            }
        }
    }
}
